/****************************************************************************
 * Copyright (C) 2009-2013 Dimok
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ****************************************************************************/
#include "../Themes/CTheme.h"
#include "HorizontalScrollbar.hpp"
//#include "../Tools/tools.h"
#include "../System/input.h"

HorizontalScrollbar::HorizontalScrollbar(int w)
{
	SelItem = 0;
	EntrieCount = 0;
	ScrollSpeed = 15;
	ScrollState = 0;
	AllowDPad = true;
	listChanged.connect(this, &HorizontalScrollbar::setScrollboxPosition);

	btnSoundClick = Resources::GetSound("button_click.wav");
	btnSoundOver = Resources::GetSound("button_over.wav");
	btnSoundClick->SetVolume(Settings.SFXVolume);
	btnSoundOver->SetVolume(Settings.SFXVolume);
	
	scrollbarLeft = Resources::GetImageData("scrollbar_custom_top.png");
	scrollbarRight = Resources::GetImageData("scrollbar_custom_bottom.png");
	scrollbarTile = Resources::GetImageData("scrollbar_custom_tile.png");
	arrowLeft = Resources::GetImageData("scrollbar_arrowdown.png");
	arrowRight = Resources::GetImageData("scrollbar_arrowup.png");
	scrollbarBox = Resources::GetImageData("scrollbar_box.png");
	oneButtonScrollImgData = Resources::GetImageData("oneButtonScroll.png");

	width = w;
	height = MAX(scrollbarBox->GetWidth(), scrollbarTile->GetWidth());

	MinWidth = arrowLeft->GetHeight() + 3;
	MaxWidth = width-MinWidth-arrowLeft->GetHeight()-scrollbarBox->GetHeight();

	trigHeldA = new GuiTrigger;
	trigHeldA->SetHeldTrigger(-1, WiiControls.ClickButton | ClassicControls.ClickButton << 16, GCControls.ClickButton);

	int PositionX = arrowLeft->GetHeight()+10;
	int Tiles = (width-scrollbarLeft->GetHeight()-scrollbarRight->GetHeight()-(arrowLeft->GetHeight()*2))/scrollbarTile->GetHeight();
	
	scrollbarLeftImg = new GuiImage(scrollbarLeft);
	scrollbarLeftImg->SetParent(this);
	scrollbarLeftImg->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	scrollbarLeftImg->SetPosition(PositionX, 0);
	scrollbarLeftImg->SetAngle(270);
	PositionX += scrollbarLeft->GetHeight() / 2 - scrollbarTile->GetHeight();

	scrollbarTileImg = new GuiImage(scrollbarTile);
	scrollbarTileImg->SetParent(this);
	scrollbarTileImg->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	scrollbarTileImg->SetPosition(PositionX, 0);
	scrollbarTileImg->SetAngle(270);
	scrollbarTileImg->SetTileHorizontal(Tiles);
	PositionX += Tiles*scrollbarTile->GetHeight() + scrollbarLeft->GetHeight() / 2 - scrollbarTile->GetHeight();

	scrollbarRightImg = new GuiImage(scrollbarRight);
	scrollbarRightImg->SetParent(this);
	scrollbarRightImg->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	scrollbarRightImg->SetPosition(PositionX, 0);
	scrollbarRightImg->SetAngle(270);

	arrowLeftImg = new GuiImage(arrowLeft);
	arrowRightImg = new GuiImage(arrowRight);
	scrollbarBoxImg = new GuiImage(scrollbarBox);
	
	arrowLeftImg->SetAngle(90);
	arrowLeftBtn = new GuiButton(arrowLeftImg->GetWidth(), arrowLeftImg->GetHeight());
	arrowLeftBtn->SetParent(this);
	arrowLeftBtn->SetImage(arrowLeftImg);
	arrowLeftBtn->SetImageOver(arrowLeftImg);
	arrowLeftBtn->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	arrowLeftBtn->SetPosition(-6, 0);
	arrowLeftBtn->SetHoldable(true);
	arrowLeftBtn->SetTrigger(trigHeldA);
	arrowLeftBtn->SetSoundOver(btnSoundOver);
	arrowLeftBtn->SetSoundClick(btnSoundClick);
	arrowLeftBtn->SetEffectGrow();
	arrowLeftBtn->Held.connect(this, &HorizontalScrollbar::OnLeftButtonHold);

	arrowRightImg->SetAngle(90);
	arrowRightBtn = new GuiButton(arrowRightImg->GetWidth(), arrowRightImg->GetHeight());
	arrowRightBtn->SetParent(this);
	arrowRightBtn->SetImage(arrowRightImg);
	arrowRightBtn->SetImageOver(arrowRightImg);
	arrowRightBtn->SetAlignment(ALIGN_RIGHT | ALIGN_MIDDLE);
	arrowRightBtn->SetPosition(-6, 0);
	arrowRightBtn->SetHoldable(true);
	arrowRightBtn->SetTrigger(trigHeldA);
	arrowRightBtn->SetSoundOver(btnSoundOver);
	arrowRightBtn->SetSoundClick(btnSoundClick);
	arrowRightBtn->SetEffectGrow();
	arrowRightBtn->Held.connect(this, &HorizontalScrollbar::OnRightButtonHold);

	scrollbarBoxImg->SetAngle(90);
	scrollbarBoxBtn = new GuiButton(scrollbarBoxImg->GetWidth(), scrollbarBoxImg->GetHeight());
	scrollbarBoxBtn->SetParent(this);
	scrollbarBoxBtn->SetImage(scrollbarBoxImg);
	scrollbarBoxBtn->SetImageOver(scrollbarBoxImg);
	scrollbarBoxBtn->SetAlignment(ALIGN_LEFT | ALIGN_MIDDLE);
	scrollbarBoxBtn->SetPosition(MinWidth, 0);
	scrollbarBoxBtn->SetHoldable(true);
	scrollbarBoxBtn->SetTrigger(trigHeldA);
	scrollbarBoxBtn->SetEffectGrow();
	scrollbarBoxBtn->Held.connect(this, &HorizontalScrollbar::OnBoxButtonHold);
}

HorizontalScrollbar::~HorizontalScrollbar()
{
	Resources::Remove(btnSoundOver);
	Resources::Remove(btnSoundClick);
	Resources::Remove(scrollbarLeft);
	Resources::Remove(scrollbarRight);
	Resources::Remove(scrollbarTile);
	Resources::Remove(arrowLeft);
	Resources::Remove(arrowRight);
	Resources::Remove(scrollbarBox);
	Resources::Remove(oneButtonScrollImgData);

	delete arrowLeftBtn;
	delete arrowRightBtn;
	delete scrollbarBoxBtn;

	delete scrollbarLeftImg;
	delete scrollbarRightImg;
	delete scrollbarTileImg;
	delete arrowLeftImg;
	delete arrowRightImg;
	delete scrollbarBoxImg;
	
	delete trigHeldA;
}

void HorizontalScrollbar::ScrollOneLeft()
{
	if(SelItem > 0)
	{
		//! move list left by 1
		--SelItem;
	}
}

void HorizontalScrollbar::ScrollOneRight()
{
	if(SelItem + 1 < EntrieCount)
	{
		//! move list right by 1
		SelItem++;
	}
}

void HorizontalScrollbar::OnLeftButtonHold(GuiButton *sender UNUSED, int pointer UNUSED, const POINT &p UNUSED)
{
	if(ScrollState < ScrollSpeed)
		return;

	ScrollOneLeft();

	ScrollState = 0;
	listChanged(SelItem);
}

void HorizontalScrollbar::OnRightButtonHold(GuiButton *sender UNUSED, int pointer UNUSED, const POINT &p UNUSED)
{
	if(ScrollState < ScrollSpeed)
		return;

	ScrollOneRight();

	ScrollState = 0;
	listChanged(SelItem);
}

void HorizontalScrollbar::OnBoxButtonHold(GuiButton *sender UNUSED, int pointer, const POINT &p)
{
	if(ScrollState < ScrollSpeed)
		return;

	if(!userInput[pointer].wpad.ir.valid)
		return;

	int x = p.x - this->GetLeft()-scrollbarBox->GetHeight()/2;

	int positionWiimote = LIMIT(x-MinWidth, 0, MaxWidth-MinWidth);

	int newSelected = ( positionWiimote * (EntrieCount-1) ) / (MaxWidth-MinWidth);

	SelItem = LIMIT(newSelected, 0, EntrieCount-1);

	ScrollState = 0;
	listChanged(SelItem);
}

void HorizontalScrollbar::SetSelectedItem(int pos)
{
	SelItem = LIMIT(pos, 0, EntrieCount-1);
	listChanged(SelItem);
}

void HorizontalScrollbar::SetEntrieCount(int cnt)
{
	if(EntrieCount == cnt)
		return;

	EntrieCount = cnt;
	listChanged(SelItem);
}

void HorizontalScrollbar::setScrollboxPosition(int SelItem)
{
	int position = MinWidth + ( (MaxWidth-MinWidth) * SelItem ) / (EntrieCount > 1 ? EntrieCount-1 : 1);

	if(position < MinWidth)
		position = MinWidth;
	else if(position > MaxWidth || (SelItem >= EntrieCount-1))
		position = MaxWidth;

	scrollbarBoxBtn->SetPosition(position, 0);
}

void HorizontalScrollbar::CheckDPadControls(GuiTrigger *t)
{
	if(t->Left())
	{
		ScrollOneLeft();
		listChanged(SelItem);
	}
	else if(t->Right())
	{
		ScrollOneRight();
		listChanged(SelItem);
	}
}

void HorizontalScrollbar::Draw()
{
	scrollbarTileImg->Draw();
	scrollbarLeftImg->Draw();
	scrollbarRightImg->Draw();
	arrowLeftBtn->Draw();
	arrowRightBtn->Draw();
	scrollbarBoxBtn->Draw();

	UpdateEffects();
}

void HorizontalScrollbar::Update(GuiTrigger * t)
{
	if(!t || state == STATE_DISABLED)
		return;

	arrowLeftBtn->Update(t);
	arrowRightBtn->Update(t);
	scrollbarBoxBtn->Update(t);
	if(AllowDPad)
		CheckDPadControls(t);

	++ScrollState;
}

void HorizontalScrollbar::SetBounds(iRect w)
{
	GuiElement::SetBounds(w);
	scrollbarLeftImg->SetBounds(w);
	scrollbarRightImg->SetBounds(w);
	scrollbarTileImg->SetBounds(w);
	arrowLeftImg->SetBounds(w);
	arrowRightImg->SetBounds(w);
	scrollbarBoxImg->SetBounds(w);
}
